package com.kinghood.productcenter.service.base.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.kinghood.infrastructure.api.authority.SysLogModuleEnum;
import com.kinghood.infrastructure.api.authority.UserRemoteVo;
import com.kinghood.infrastructure.model.KingHoodException;
import com.kinghood.infrastructure.model.constant.CommonConstants;
import com.kinghood.infrastructure.model.enums.StatusEnum;
import com.kinghood.infrastructure.util.UserUtil;
import com.kinghood.infrastructure.util.base.IdGenUtil;
import com.kinghood.infrastructure.util.excel.EasyExcelUtil;
import com.kinghood.productcenter.common.api.authority.UserRemote;
import com.kinghood.productcenter.common.model.dao.base.BaseGoodsDO;
import com.kinghood.productcenter.common.model.dao.product.DownloadCenterDO;
import com.kinghood.productcenter.common.model.dao.product.ProductBaseDO;
import com.kinghood.productcenter.common.model.dto.MoveChangeSortReqDTO;
import com.kinghood.infrastructure.model.dto.StatusReqDTO;
import com.kinghood.productcenter.common.model.dto.base.GoodsQueryDTO;
import com.kinghood.productcenter.common.model.dto.base.GoodsReqDTO;
import com.kinghood.productcenter.common.model.excel.GoodsExcel;
import com.kinghood.productcenter.common.model.vo.base.GoodsVO;
import com.kinghood.productcenter.common.utils.UserNameUtil;
import com.kinghood.productcenter.dao.base.BaseGoodsMapper;
import com.kinghood.productcenter.service.async.IAsyncHuaWeiYunService;
import com.kinghood.productcenter.service.base.IBaseGoodsService;
import com.kinghood.productcenter.service.product.IDownloadCenterService;
import com.kinghood.productcenter.service.product.IProductBaseService;
import com.kinghood.productcenter.service.product.handler.ProductBaseHandler;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 基础选项-货类 服务实现类
 * </p>
 *
 * @author KingHood
 * @since 2023-12-20
 */
@Service
public class BaseGoodsServiceImpl extends ServiceImpl<BaseGoodsMapper, BaseGoodsDO> implements IBaseGoodsService {
    @Resource
    private IProductBaseService productBaseService;
    @Value("${base.uploadPath}")
    private String uploadPath;
    @Resource
    private UserRemote userRemote;
    @Resource
    private IDownloadCenterService downloadCenterService;
    @Resource
    private IAsyncHuaWeiYunService asyncUploadHuaWeiYun;

    /**
     * 列出所有品类
     *
     * @param param 参数
     * @author jp
     * @date 2023/12/27
     */
    @Override
    public List<GoodsVO> listAllGoods(GoodsQueryDTO param) {
        List<GoodsVO> dataList = getAllGoods(param);

        return dataList.stream().filter(tree -> Objects.isNull(tree.getParentId()))
                .peek((dept) -> dept.setChildren(getChildrenNode(dept, dataList))).collect(Collectors.toList());
    }

    /**
     * 商品数据不分层
     *
     * @param param 参数
     * @return @return {@link List }<{@link GoodsVO }>
     * @author jp
     * @date 2024/01/11 09:13
     */
    private List<GoodsVO> getAllGoods(GoodsQueryDTO param) {
        List<GoodsVO> dataList = this.baseMapper.listAllGoods(param);
        List<Long> allIds = dataList.stream().map(GoodsVO::getIdPath)
                .flatMap(str -> Arrays.stream(str.split("/")))
                .map(Long::valueOf)
                .collect(Collectors.toList());
        List<Long> existids = dataList.stream().map(GoodsVO::getId).collect(Collectors.toList());
        allIds.removeAll(existids);
        if (!CollectionUtils.isEmpty(allIds)) {
            GoodsQueryDTO two = new GoodsQueryDTO();
            two.setIdList(allIds);
            dataList.addAll(this.baseMapper.listAllGoods(two));
        }

        for (GoodsVO goodsVO : dataList) {
            goodsVO.setCodeName("["+goodsVO.getGoodsCode()+"]"+goodsVO.getGoodsName());
        }

        Set<Long> userIdList = new HashSet<>();
        for (GoodsVO record : dataList) {
            userIdList.add(record.getCreateUserId());
            userIdList.add(record.getUpdateUserId());
            record.setStatusTxt(StatusEnum.getNameByStatus(record.getStatus()));
        }
        userIdList.remove(null);
        if (!CollectionUtils.isEmpty(userIdList)) {
            Map<Long, UserRemoteVo> userMap = userRemote.getUserByIds(new ArrayList<Long>(userIdList));
            for (GoodsVO record : dataList) {
                record.setCreateUserName(UserNameUtil.getName(record.getCreateUserId(), userMap));
                record.setUpdateUserName(UserNameUtil.getName(record.getUpdateUserId(), userMap));
            }
        }
        return dataList;
    }

    /**
     * 获取子节点
     *
     * @param parent  parent
     * @param dtoList dto列表
     * @author jp
     * @date 2023/12/26
     */
    private List<GoodsVO> getChildrenNode(GoodsVO parent, List<GoodsVO> dtoList) {
        return dtoList.stream().filter((tree) -> Objects.nonNull(tree.getParentId()) && tree.getParentId().equals(parent.getId()))
                .peek((tree) -> tree.setChildren(getChildrenNode(tree, dtoList))).collect(Collectors.toList());
    }

    /**
     * 添加或更新
     *
     * @param param 参数
     * @author jp
     * @date 2023/12/27
     */
    @Override
    public void addOrUpdateGoods(GoodsReqDTO param) {
        checkOnly(param);
        BaseGoodsDO goods = new BaseGoodsDO();
        BeanUtils.copyProperties(param, goods);
        LocalDateTime now = LocalDateTime.now();
        if (Objects.isNull(param.getId())) {
            goods.setId(IdGenUtil.get().nextId());
            goods.setCreateTime(now);
            goods.setCreateUserId(UserUtil.getUserId());
            goods.setUpdateTime(now);
            goods.setSort(0);
            goods.setUpdateUserId(UserUtil.getUserId());
            if (Objects.isNull(param.getParentId())) {
                goods.setIdPath(goods.getId() + "");
                goods.setNamePath(goods.getGoodsName());
                goods.setLevel(1);
            } else {
                BaseGoodsDO parent = this.getById(param.getParentId());
                goods.setIdPath(parent.getIdPath() + "/" + goods.getId());
                goods.setNamePath(parent.getNamePath() + "/" + goods.getGoodsName());
                goods.setLevel(parent.getLevel() + 1);
            }
            // 设置同级其它sort+1
            this.baseMapper.addSortExcludeId(goods);
            this.save(goods);
        } else {
            BaseGoodsDO old = this.getById(param.getId());

            if (param.getStatus() == CommonConstants.DISABLE) {
                long count = this.lambdaQuery().eq(BaseGoodsDO::getIsDelete, CommonConstants.IS_DELETE_N)
                        .eq(BaseGoodsDO::getStatus, CommonConstants.ENABLE)
                        .like(BaseGoodsDO::getIdPath, old.getIdPath())
                        .ne(BaseGoodsDO::getId, param.getId())
                        .count();
                if (count > 0) {
                    throw new KingHoodException(-1, "下层有启用状态，无法停用");
                }
            }

            goods.setParentId(old.getParentId());
            goods.setUpdateTime(now);
            goods.setUpdateUserId(UserUtil.getUserId());
            this.updateById(goods);
        }
    }

    /**
     * 检查是否唯一
     *
     * @param param 参数
     * @author jp
     * @date 2023/12/21
     */
    private void checkOnly(GoodsReqDTO param) {
        Long count = 0l;
        if (Objects.isNull(param.getId())) {
            count = this.lambdaQuery().eq(BaseGoodsDO::getGoodsCode, param.getGoodsCode())
                    .eq(BaseGoodsDO::getIsDelete, CommonConstants.IS_DELETE_N)
                    .count();
            if (count > 0) {
                throw new KingHoodException(-1, "编码已存在");
            }
            count = this.lambdaQuery().eq(BaseGoodsDO::getGoodsName, param.getGoodsName())
                    .eq(BaseGoodsDO::getIsDelete, CommonConstants.IS_DELETE_N)
                    .eq(BaseGoodsDO::getParentId, param.getParentId())
                    .count();
            if (count > 0) {
                throw new KingHoodException(-1, "名称已存在");
            }
        } else {
            count = this.lambdaQuery().eq(BaseGoodsDO::getGoodsCode, param.getGoodsCode())
                    .ne(BaseGoodsDO::getId, param.getId())
                    .eq(BaseGoodsDO::getIsDelete, CommonConstants.IS_DELETE_N)
                    .count();
            if (count > 0) {
                throw new KingHoodException(-1, "编码已存在");
            }
            count = this.lambdaQuery().eq(BaseGoodsDO::getGoodsName, param.getGoodsName())
                    .ne(BaseGoodsDO::getId, param.getId())
                    .eq(BaseGoodsDO::getIsDelete, CommonConstants.IS_DELETE_N)
                    .eq(BaseGoodsDO::getParentId, param.getParentId())
                    .count();
            if (count > 0) {
                throw new KingHoodException(-1, "名称已存在");
            }
        }
    }

    /**
     * 更新状态
     *
     * @param param 参数
     * @author jp
     * @date 2023/12/27
     */
    @Override
    public void updateGoodsStatus(StatusReqDTO param) {
        this.lambdaUpdate().set(BaseGoodsDO::getStatus, param.getStatus())
                .set(BaseGoodsDO::getUpdateTime, LocalDateTime.now())
                .set(BaseGoodsDO::getUpdateUserId, UserUtil.getUserId())
                .eq(BaseGoodsDO::getId, param.getId())
                .eq(BaseGoodsDO::getIsDelete, CommonConstants.IS_DELETE_N)
                .update();
    }

    /**
     * 删除
     *
     * @param id id
     * @author jp
     * @date 2023/12/27
     */
    @Override
    public void delGoods(Long id) {
        BaseGoodsDO category = this.getById(id);
        if (Objects.isNull(category)) {
            return;
        }
        if (Objects.nonNull(category) && !category.getStatus().equals(CommonConstants.DISABLE)) {
            throw new KingHoodException(-1, "只有停用状态的才可操作删除");
        }
        long childCount = this.lambdaQuery().eq(BaseGoodsDO::getParentId, id)
                .eq(BaseGoodsDO::getIsDelete, CommonConstants.IS_DELETE_N)
                .count();
        if (childCount > 0) {
            throw new KingHoodException(-1, "存在下级货类，请移除后再删除");
        }
        long productCount = productBaseService.lambdaQuery().eq(ProductBaseDO::getIsDelete, CommonConstants.IS_DELETE_N)
                .eq(ProductBaseDO::getGoodsId, id)
                .count();
        if (productCount > 0) {
            throw new KingHoodException(-1, "该货类下已绑定款式，请移除后再删除");
        }
        this.lambdaUpdate().set(BaseGoodsDO::getIsDelete, CommonConstants.IS_DELETE_Y)
                .set(BaseGoodsDO::getUpdateTime, LocalDateTime.now())
                .set(BaseGoodsDO::getUpdateUserId, UserUtil.getUserId())
                .eq(BaseGoodsDO::getId, id)
                .update();
        // 比当前数据sort大的，sort-1
        this.baseMapper.sortMinusOne(category);
    }

    /**
     * 详细
     *
     * @param id id
     * @author jp
     * @date 2023/12/28
     */
    @Override
    public GoodsVO detailGoods(Long id) {
        GoodsVO result=new GoodsVO();
        BaseGoodsDO goods = this.lambdaQuery().eq(BaseGoodsDO::getIsDelete, CommonConstants.IS_DELETE_N)
                .eq(BaseGoodsDO::getId, id)
                .one();
        if (Objects.nonNull(goods)) {
            BeanUtils.copyProperties(goods, result);
            return result;
        }
        return null;
    }

    /**
     * 拖动更改排序
     *
     * @param param 参数
     * @author jp
     * @date 2023/12/28
     */
    @Override
    public void changeSort(MoveChangeSortReqDTO param) {
        BaseGoodsDO moveOne = this.getById(param.getId());
        if (Objects.isNull(param.getNextId())) {
            this.baseMapper.addSortLessThanThis(moveOne);
            this.lambdaUpdate().set(BaseGoodsDO::getSort, 0)
                    .eq(BaseGoodsDO::getId, moveOne.getId())
                    .update();
        } else {
            BaseGoodsDO nextOne = this.getById(param.getNextId());
            if (Objects.isNull(moveOne) || Objects.isNull(nextOne)) {
                throw new KingHoodException(-1, "移动的数据不能为空");
            }
            if (Objects.nonNull(moveOne.getParentId()) && Objects.nonNull(nextOne.getParentId()) && !moveOne.getParentId().equals(nextOne.getParentId())) {
                throw new KingHoodException(-1, "只能同级数据才能移动");
            }
            // 两个互换sort
            this.lambdaUpdate().set(BaseGoodsDO::getSort, nextOne.getSort())
                    .eq(BaseGoodsDO::getId, moveOne.getId())
                    .update();
            this.lambdaUpdate().set(BaseGoodsDO::getSort, moveOne.getSort())
                    .eq(BaseGoodsDO::getId, nextOne.getId())
                    .update();
        }
    }

    /**
     * 下载
     *
     * @param param    参数
     * @param response 回答
     * @return
     * @author jp
     * @date 2024/01/12 14:55
     */
    @Override
    public void downloadGoods(GoodsQueryDTO param, HttpServletResponse response) {
        String fileName = StringUtils.isEmpty(param.getFileName()) ? "货类数据" : param.getFileName();
        String sheetName = StringUtils.isEmpty(param.getSheetName()) ? "货类" : param.getSheetName();

        List<GoodsVO> dataList = getAllGoods(param);
        List<GoodsExcel> result = new ArrayList<>();
        for (GoodsVO goodsVO : dataList) {
            GoodsExcel excel = new GoodsExcel();
            BeanUtils.copyProperties(goodsVO, excel);
            result.add(excel);
        }
        // 保存到数据库
        LocalDateTime now = LocalDateTime.now();
        DownloadCenterDO downloadCenterDO = new DownloadCenterDO();
        try {
            String showParam = "";
            if (!CollectionUtils.isEmpty(param.getDownloadField())) {
                showParam = String.join(",", param.getDownloadField());
            }
            String path = EasyExcelUtil.export(response, fileName, sheetName, result, GoodsExcel.class,
                    showParam, uploadPath);
            File file = new File(path);
            downloadCenterDO.setId(IdGenUtil.getId())
                    .setFileName(file.getName())
                    .setModule(SysLogModuleEnum.PRODUCT_GOODS.getType())
                    .setType(2)
                    .setFileSize(ProductBaseHandler.getSizeName(file.length()))
                    .setUrl(path)
                    .setCreateTime(now)
                    .setUpdateTime(now)
                    .setCreateUserId(UserUtil.getUserId())
                    .setUpdateUserId(UserUtil.getUserId());
            downloadCenterService.save(downloadCenterDO);
            asyncUploadHuaWeiYun.uploadToHuaWeiYun(downloadCenterDO.getId(), file.getAbsolutePath());
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}